package com.lry.jvm.rtda;

import com.lry.jvm.rtda.heap.JClass;
import com.lry.jvm.rtda.heap.JField;
import com.lry.jvm.util.Util;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

//    其次，创建数组的方式和创建普通对象的方式不同。
//        普通对象 由new指令创建，然后由构造函数初始化。
//        基本类型数组由newarray 指令创建；引用类型数组由anewarray指令创建；
//        另外还有一个专门 的multianewarray指令用于创建多维数组。
//        最后，很显然，数组和普通对象存放的数据也是不同的。
//        普通 对象中存放的是实例变量，通过putfield和getfield指令存取。
//        数组对 象中存放的则是数组元素，通过<t>aload和<t>astore系列指令按索
//        引存取。其中<t>可以是a、b、c、d、f、i、l或者s，分别用于存取引用、
//        byte、char、double、float、int、long或short类型的数组。
//        另外，还有一 个arraylength指令，用于获取数组长度。
public class JObject {

    private JClass jClass;

    //实例变量/数组
    private Object data;

    private Object extra;

    //给实例变量实例化调用
    public JObject(JClass jClass){
        this.jClass = jClass;
        this.data = new LocalVars(jClass.getInstanceSlotCount());
    }

    //给数组变量实例化调用
    public JObject(JClass jClass,Object data){
        this.jClass = jClass;
        this.data = data;
    }

    public Object getExtra() {
        return extra;
    }

    public void setExtra(Object extra) {
        this.extra = extra;
    }

    public JClass getJClass() {
        return jClass;
    }

    public LocalVars getInstanceVars() {
        return (LocalVars) data;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public byte[] toBytes(){
        return (byte[]) data;
    }

    public short[] toShorts(){
        return (short[]) data;
    }

    public int[] toInts(){
        return (int[]) data;
    }

    public long[] toLongs(){
        return (long[]) data;
    }

    public char[] toChars(){
        return (char[]) data;
    }

    public float[] toFloats(){
        return (float[]) data;
    }

    public double[] toDoubles(){
        return (double[]) data;
    }

    public JObject[] toRefs(){
        return (JObject[]) data;
    }

    public int arrayLength(){
        Object obj = data;
        if(obj instanceof byte[]){
            return toBytes().length;
        }else if(obj instanceof short[]){
            return toShorts().length;
        }else if(obj instanceof int[]){
            return toInts().length;
        }else if(obj instanceof long[]){
            return toLongs().length;
        }else if(obj instanceof char[]){
            return toChars().length;
        }else if(obj instanceof float[]){
            return toFloats().length;
        }else if(obj instanceof double[]){
            return toDoubles().length;
        }else if(obj instanceof JObject[]){
            return toRefs().length;
        }else {
            Util.panic("Not array!");
            return 0;
        }
    }

    public boolean isInstanceOf(JClass jClass){
        return jClass.isAssignableFrom(this.jClass);
    }

    public void setRefVar(String name, String descriptor, JObject ref) {
        JField field = jClass.getField(name,descriptor,false);
        LocalVars slots = (LocalVars)data;
        slots.setRef(field.getSlotId(),ref);
    }

    public JObject getRefVar(String name, String descriptor){
        JField field = jClass.getField(name,descriptor,false);
        LocalVars slots = (LocalVars)data;
        return slots.getRef(field.getSlotId());
    }

    //todo
    public JObject cloneObj() {
        return this;
    }
}
